package com.sg.fileService.util;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.IOException;

import java.io.InputStream;

import java.util.Enumeration;

import org.apache.commons.lang3.StringUtils;
import org.apache.tools.zip.ZipEntry;

import org.apache.tools.zip.ZipFile;

import org.apache.tools.zip.ZipOutputStream;

import lombok.extern.slf4j.Slf4j;

/**
 * 
 * java文件操作工具类
 * 
 * 此类包含利用JAVA进行文件的压缩,解压,删除,拷贝操作。部分代码总结了网上的代码,并修正了很多BUG,例如压缩中文问题, 压缩文件中多余空文件问题。
 * 
 * 注意:此类中用到的压缩类ZipEntry等都来自于org.apache.tools包而非java.util。此包在ant.jar中有。
 * 
 * @
 */
@Slf4j
public class FileUtil {
	private static final int BUFFER_SIZE = 16 * 1024;
	
	private static final String PATH_CAN_NOT_EMPTY = "sourcePath cannot be empty.";

	/**
	 * 
	 * 压缩文件
	 * 
	 * @param inputFileName
	 *            要压缩的文件或文件夹路径,例如:c://a.txt,c://a/
	 * 
	 * @param outputFileName
	 *            输出zip文件的路径,例如:c://a.zip
	 */

	public static void main(String[] args) {

		log.info("test");

	}

	public static void zip(String inputFileName, String outputFileName) throws Exception {

		ZipOutputStream out = new ZipOutputStream(new FileOutputStream(outputFileName));

		zip(out, new File(inputFileName), "");

		log.debug("压缩完成!");

		out.closeEntry();

		out.close();

	}

	/**
	 * 
	 * 压缩文件
	 * 
	 * @param out
	 *            org.apache.tools.zip.ZipOutputStream
	 * 
	 * @param file
	 *            待压缩的文件
	 * 
	 * @param base
	 *            压缩的根目录
	 */

	private static void zip(ZipOutputStream out, File file, String base) throws Exception {

		if (file.isDirectory()) {

			File[] fl = file.listFiles();

			base = base.length() == 0 ? "" : base + File.separator;

			for (int i = 0; i < fl.length; i++) {

				zip(out, fl[i], base + fl[i].getName());

			}

		} else {

			out.putNextEntry(new ZipEntry(base));

			log.debug("添加压缩文件:" + base);

			try (FileInputStream in = new FileInputStream(file);) {

				int b;

				while ((b = in.read()) != -1) {

					out.write(b);

				}
			}

		}

	}

	/**
	 * 
	 * 解压zip文件
	 * 
	 * @param zipFileName
	 *            待解压的zip文件路径,例如:c://a.zip
	 * 
	 * @param outputDirectory
	 *            解压目标文件夹,例如:c://a/
	 * @throws IOException
	 */

	public static void unZip(String zipFileName, String outputDirectory) throws IOException {

		try (ZipFile zipFile = new ZipFile(zipFileName);) {

			Enumeration<?> e = zipFile.getEntries();

			ZipEntry zipEntry = null;

			createDirectory(outputDirectory, "");

			while (e.hasMoreElements()) {

				zipEntry = (ZipEntry) e.nextElement();

				log.debug("解压:" + zipEntry.getName());

				if (zipEntry.isDirectory()) {

					String name = zipEntry.getName();

					name = name.substring(0, name.length() - 1);

					File f = new File(outputDirectory + File.separator + name);

					f.mkdir();

					log.debug("创建目录:" + outputDirectory + File.separator + name);

				} else {

					String fileName = zipEntry.getName();

					fileName = PathCreator.fomartPath(fileName);

					if (fileName.indexOf(File.separator) != -1) {

						createDirectory(outputDirectory, fileName.substring(0, fileName.lastIndexOf(File.separator)));

						fileName = fileName.substring(fileName.lastIndexOf(File.separator) + 1, fileName.length());

					}

					File f = new File(outputDirectory + File.separator + zipEntry.getName());

					if (f.createNewFile()) {
						try (InputStream in = zipFile.getInputStream(zipEntry);
								FileOutputStream out = new FileOutputStream(f);) {

							byte[] by = new byte[1024];

							int c;

							while ((c = in.read(by)) != -1) {

								out.write(by, 0, c);

							}

						}
					}

				}

			}

		} catch (Exception ex) {

			log.info(ex.getMessage());

		} finally {

			log.debug("解压完成!");

		}

	}

	private static void createDirectory(String directory, String subDirectory) {


		File fl = new File(directory);

		StringBuilder sb = new StringBuilder(directory);

		try {

			if (subDirectory == "" && !fl.exists()) {

				fl.mkdir();

			} else if (subDirectory != "") {

				String dir[] = PathCreator.fomartPath(subDirectory).split(File.separator);

				for (int i = 0; i < dir.length; i++) {

					File subFile = new File(directory + File.separator + dir[i]);

					if (!subFile.exists())

						subFile.mkdir();

					sb.append(File.separator + dir[i]);

				}

			}

		} catch (Exception ex) {

			log.debug(ex.getMessage());

		}

	}

	/**
	 * 
	 * 拷贝文件夹中的所有文件到另外一个文件夹
	 * 
	 * @param srcDirector
	 *            源文件夹
	 * 
	 * @param desDirector
	 *            目标文件夹
	 */

	public static void copyFileWithDirector(String srcDirector, String desDirector) throws IOException {

		(new File(desDirector)).mkdirs();

		File[] file = (new File(srcDirector)).listFiles();

		for (int i = 0; i < file.length; i++) {

			if (file[i].isFile()) {

				log.debug("拷贝:" + file[i].getAbsolutePath() + "-->" + desDirector + File.separator + file[i].getName());

				try (FileInputStream input = new FileInputStream(file[i]);

						FileOutputStream output = new FileOutputStream(
								desDirector + File.separator + file[i].getName());) {

					byte[] b = new byte[1024 * 5];

					int len;

					while ((len = input.read(b)) != -1) {

						output.write(b, 0, len);

					}

					output.flush();
				}

			}

			if (file[i].isDirectory()) {

				log.debug("拷贝:" + file[i].getAbsolutePath() + "-->" + desDirector + File.separator + file[i].getName());

				copyFileWithDirector(srcDirector + File.separator + file[i].getName(),
						desDirector + File.separator + file[i].getName());

			}

		}

	}

	/**
	 * 
	 * 删除文件夹
	 * 
	 * @param folderPath
	 *            folderPath 文件夹完整绝对路径
	 */

	public static void delFolder(String folderPath) throws Exception {

		// 删除完里面所有内容

		delAllFile(folderPath);

		Files.delete(Paths.get(folderPath));
	}

	/**
	 * 
	 * 删除指定文件夹下所有文件
	 * 
	 * @param path
	 *            文件夹完整绝对路径
	 */

	public static boolean delAllFile(String path) throws Exception {

		boolean flag = false;

		File file = new File(path);

		if (!file.exists()) {

			return flag;

		}

		if (!file.isDirectory()) {

			return flag;

		}

		String[] tempList = file.list();

		File temp = null;

		for (int i = 0; i < tempList.length; i++) {

			if (path.endsWith(File.separator)) {

				temp = new File(path + tempList[i]);

			} else {

				temp = new File(path + File.separator + tempList[i]);

			}

			if (temp.isFile()) {
				Files.delete(Paths.get(temp.getPath()));

			}

			if (temp.isDirectory()) {

				// 先删除文件夹里面的文件

				delAllFile(path + File.separator + tempList[i]);

				// 再删除空文件夹

				delFolder(path + File.separator + tempList[i]);

				flag = true;

			}

		}

		return flag;

	}

	/**
	 * 功能描述:列出某文件夹及其子文件夹下面的文件,并可根据扩展名过滤
	 * 
	 * @param path
	 *            文件夹
	 */
	public static void list(File path) {
		if (!path.exists()) {
			log.debug("文件名称不存在!");
		} else {
			if (path.isFile()) {
				if (path.getName().toLowerCase().endsWith(".pdf") || path.getName().toLowerCase().endsWith(".doc")
						|| path.getName().toLowerCase().endsWith(".chm")
						|| path.getName().toLowerCase().endsWith(".html")
						|| path.getName().toLowerCase().endsWith(".htm")) {// 文件格式
					log.info(path.toString());
					log.info(path.getName());
				}
			} else {
				File[] files = path.listFiles();
				for (int i = 0; i < files.length; i++) {
					list(files[i]);
				}
			}
		}
	}

	/**
	 * 功能描述:拷贝一个目录或者文件到指定路径下,即把源文件拷贝到目标文件路径下
	 * 
	 * @param source
	 *            源文件
	 * @param target
	 *            目标文件路径
	 * @return void
	 * @throws IOException
	 */
	public static void copy(File source, File target){

		String tarpath = target.getParent();

		File targetParent = new File(tarpath);

		try (InputStream is = new FileInputStream(source); // 用于读取文件的原始字节流
				OutputStream os = new FileOutputStream(target); // 用于写入文件的原始字节的流
				){
			if (!targetParent.exists()) {
				targetParent.mkdirs();
			}
			
			byte[] buf = new byte[1024];// 存储读取数据的缓冲区大小
			int len = 0;
			while ((len = is.read(buf)) != -1) {
				os.write(buf, 0, len);
			}
		} catch (IOException e) {
			log.debug(e.getMessage());
		} 

	}

	/**
	 * 功能描述:拷贝一个目录或者文件到指定路径下,即把源文件拷贝到目标文件路径下
	 * 
	 * @param source
	 *            源文件路径
	 * @param target
	 *            目标文件路径
	 * @return void
	 * @throws IOException
	 */
	public static void copy(String source, String target){
		if (StringUtils.isEmpty(source)||StringUtils.isEmpty(target)) {
			throw new NullPointerException(FileUtil.PATH_CAN_NOT_EMPTY);
		}
		copy(new File(source), new File(target));
	}

	/*
	 * copy这个方法主要是用来实现文件上传的,实现的原理就是分别打开输入输出流,进行文件拷贝的
	 */
	public void copyFile(File src, File dist) {
		

		try (InputStream in = new BufferedInputStream(new FileInputStream(src), BUFFER_SIZE);
			BufferedOutputStream out = new BufferedOutputStream(new FileOutputStream(dist), BUFFER_SIZE);){
			byte[] buffer = new byte[BUFFER_SIZE];
			int len = 0;
			while ((len = in.read(buffer)) > 0) {
				out.write(buffer, 0, len);
			}
		} catch (IOException e) {
			log.debug(e.getMessage());
		} 

	}

	/*
	 * copy这个方法主要是用来实现文件上传的,实现的原理就是分别打开输入输出流,进行文件拷贝的
	 */
	public void copyFile(String src, String dist) {
		if (StringUtils.isEmpty(src)||StringUtils.isEmpty(dist)) {
			throw new NullPointerException(FileUtil.PATH_CAN_NOT_EMPTY);
		}
		copyFile(new File(src), new File(dist));
	}
}
